using System;
using System.Text;
using Oracle.ManagedDataAccess.Client;
using OracleInternal.Common;
using OracleInternal.MTS;
using OracleInternal.Network;
using OracleInternal.ServiceObjects;

namespace OracleInternal.TTC
{
	internal class TTCTransactionSE : TTCFunction
	{
		internal const int OTXSTA = 1;

		internal const int OTXDET = 2;

		internal const int OCI_TRANS_NEW = 1;

		internal const int OCI_TRANS_JOIN = 2;

		internal const int OCI_TRANS_RESUME = 4;

		internal const int OCI_TRANS_PROMOTE = 8;

		internal const int OCI_TRANS_STARTMASK = 255;

		internal const int OCI_TRANS_READONLY = 256;

		internal const int OCI_TRANS_READWRITE = 512;

		internal const int OCI_TRANS_SERIALIZABLE = 1024;

		internal const int OCI_TRANS_ISOLMASK = 65280;

		internal const int OCI_TRANS_LOOSE = 65536;

		internal const int OCI_TRANS_TIGHT = 131072;

		internal const int OCI_TRANS_TYPEMASK = 983040;

		internal const int OCI_TRANS_NOMIGRATE = 1048576;

		internal const int OCI_TRANS_SEPARABLE = 2097152;

		internal const int OCI_TRANS_OTSRESUME = 4194304;

		internal TTCTransactionSE(MarshallingEngine mEngine)
			: base(mEngine, 103, 0)
		{
		}

		private byte[] DoTransaction(int txnOperation, OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint txnFlag, uint timeout, ref long applicationValue, string connectionInternalName, string connectionExternalName)
		{
			WriteFunctionHeader();
			WriteTxnOperation(txnOperation, xid, txnCtx, txnFlag, timeout, applicationValue, connectionInternalName, connectionExternalName);
			ReadResponse(out var txnCtx2, out var applicationValue2);
			applicationValue = applicationValue2;
			return txnCtx2;
		}

		internal byte[] Start(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, ref long applicationValue)
		{
			return Start(xid, txnCtx, timeout, ref applicationValue, null, null);
		}

		internal byte[] Start(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, ref long applicationValue, string connectionInternalName, string connectionExternalName)
		{
			return DoTransaction(1, xid, txnCtx, 1u, timeout, ref applicationValue, connectionInternalName, connectionExternalName);
		}

		internal byte[] Resume(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, ref long applicationValue)
		{
			return Resume(xid, txnCtx, timeout, ref applicationValue, null, null);
		}

		internal byte[] Resume(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, ref long applicationValue, string connectionInternalName, string connectionExternalName)
		{
			return DoTransaction(1, xid, txnCtx, 4u, timeout, ref applicationValue, connectionInternalName, connectionExternalName);
		}

		internal byte[] Promote(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, ref long applicationValue)
		{
			return Promote(xid, txnCtx, timeout, ref applicationValue, null, null);
		}

		internal byte[] Promote(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, ref long applicationValue, string connectionInternalName, string connectionExternalName)
		{
			return DoTransaction(1, xid, txnCtx, 8u, timeout, ref applicationValue, connectionInternalName, connectionExternalName);
		}

		internal byte[] Detach(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, ref long applicationValue)
		{
			return Detach(xid, txnCtx, 0u, ref applicationValue, null, null);
		}

		internal byte[] Detach(OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint timeout, ref long applicationValue, string connectionInternalName, string connectionExternalName)
		{
			return DoTransaction(2, xid, txnCtx, 0u, timeout, ref applicationValue, connectionInternalName, connectionExternalName);
		}

		internal void WriteTxnOperation(int txnOpCode, OpoDTCTxnXIDRefCtx xid, byte[] txnCtx, uint txnFlag, uint timeout, long applicationValue, string connectionInternalName, string connectionExternalName)
		{
			byte[] array = null;
			byte[] array2 = null;
			bool flag = true;
			m_marshallingEngine.MarshalSWORD(txnOpCode);
			if (txnCtx == null || (txnOpCode == 1 && txnFlag == 1))
			{
				flag = false;
			}
			if (flag)
			{
				m_marshallingEngine.MarshalPointer();
				m_marshallingEngine.MarshalUB4(txnCtx.Length);
			}
			else
			{
				m_marshallingEngine.MarshalNullPointer();
				m_marshallingEngine.MarshalUB4(0L);
			}
			if (xid != null)
			{
				m_marshallingEngine.MarshalUB4(xid.m_formatID);
				m_marshallingEngine.MarshalUB4(xid.m_gtrid_length);
				m_marshallingEngine.MarshalUB4(xid.m_bqual_length);
				m_marshallingEngine.MarshalPointer();
				m_marshallingEngine.MarshalUB4(xid.m_data.Length);
			}
			else
			{
				m_marshallingEngine.MarshalUB4(0L);
				m_marshallingEngine.MarshalUB4(0L);
				m_marshallingEngine.MarshalUB4(0L);
				m_marshallingEngine.MarshalNullPointer();
				m_marshallingEngine.MarshalUB4(0L);
			}
			m_marshallingEngine.MarshalUB4(txnFlag);
			m_marshallingEngine.MarshalUB4(timeout);
			m_marshallingEngine.MarshalPointer();
			m_marshallingEngine.MarshalPointer();
			m_marshallingEngine.MarshalPointer();
			if (m_marshallingEngine.NegotiatedTTCVersion >= 5)
			{
				if (connectionInternalName != null || connectionExternalName != null)
				{
					UTF8Encoding uTF8Encoding = new UTF8Encoding();
					if (connectionInternalName != null)
					{
						array = uTF8Encoding.GetBytes(connectionInternalName);
						m_marshallingEngine.MarshalPointer();
						m_marshallingEngine.MarshalUB4(array.Length);
					}
					else
					{
						m_marshallingEngine.MarshalNullPointer();
						m_marshallingEngine.MarshalUB4(0L);
					}
					if (connectionExternalName != null)
					{
						array2 = uTF8Encoding.GetBytes(connectionExternalName);
						m_marshallingEngine.MarshalPointer();
						m_marshallingEngine.MarshalUB4(array2.Length);
					}
					else
					{
						m_marshallingEngine.MarshalNullPointer();
						m_marshallingEngine.MarshalUB4(0L);
					}
				}
				else
				{
					m_marshallingEngine.MarshalNullPointer();
					m_marshallingEngine.MarshalUB4(0L);
					m_marshallingEngine.MarshalNullPointer();
					m_marshallingEngine.MarshalUB4(0L);
				}
			}
			if (flag)
			{
				m_marshallingEngine.MarshalB1Array(txnCtx);
			}
			if (xid != null)
			{
				m_marshallingEngine.MarshalB1Array(xid.m_data);
			}
			m_marshallingEngine.MarshalUB4(applicationValue);
			if (m_marshallingEngine.NegotiatedTTCVersion >= 5)
			{
				if (array != null)
				{
					m_marshallingEngine.MarshalCHR(array);
				}
				if (array2 != null)
				{
					m_marshallingEngine.MarshalCHR(array2);
				}
			}
		}

		internal void ReadResponse(out byte[] txnCtx, out long applicationValue)
		{
			if (ProviderConfig.m_bTraceLevelPrivate)
			{
				Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)131328, OracleTraceClassName.TTCTransactionSE, OracleTraceFuncName.ReadResponse);
			}
			bool flag = false;
			byte b = 0;
			txnCtx = null;
			applicationValue = 0L;
			try
			{
				m_marshallingEngine.TTCErrorObject.Initialize();
				while (!flag)
				{
					try
					{
						switch (m_marshallingEngine.UnmarshalSB1())
						{
						case 23:
							ProcessServerSidePiggybackFunction(0);
							break;
						case 8:
							Process_RPA_Message(out txnCtx, out applicationValue);
							break;
						case 15:
							m_marshallingEngine.TTCErrorObject.ReadWarning();
							break;
						case 4:
							flag = true;
							m_marshallingEngine.TTCErrorObject.ReadErrorMessage();
							if (m_marshallingEngine.TTCErrorObject.ErrorCode == 1403)
							{
								m_marshallingEngine.TTCErrorObject.Initialize();
							}
							else
							{
								OracleConnectionImpl.CheckForAnyErrorFromDB(m_marshallingEngine.TTCErrorObject);
							}
							break;
						case 9:
							if (m_marshallingEngine.HasEOCSCapability)
							{
								m_marshallingEngine.m_endOfCallStatus = m_marshallingEngine.UnmarshalUB4();
							}
							m_marshallingEngine.UnmarshalUB4();
							flag = true;
							break;
						default:
							throw new Exception("TTC error");
						}
					}
					catch (NetworkException ex)
					{
						if (ex.ErrorCode != 3111)
						{
							throw;
						}
						m_marshallingEngine.m_oracleCommunication.Reset();
					}
					catch (Exception)
					{
						if (m_marshallingEngine.m_oraBufRdr != null)
						{
							m_marshallingEngine.m_oraBufRdr.ClearState();
						}
						if (!flag)
						{
							m_marshallingEngine.m_oracleCommunication.Break();
							m_marshallingEngine.m_oracleCommunication.Reset();
							continue;
						}
						throw;
					}
				}
			}
			catch (Exception ex3)
			{
				OracleException.HandleError(OracleTraceLevel.Private, (OracleTraceTag)268566528, OracleTraceClassName.TTCTransactionSE, OracleTraceFuncName.ReadResponse, ex3);
				throw;
			}
			finally
			{
				if (ProviderConfig.m_bTraceLevelPrivate)
				{
					Trace.Write(OracleTraceLevel.Private, (OracleTraceTag)131584, OracleTraceClassName.TTCTransactionSE, OracleTraceFuncName.ReadResponse);
				}
			}
		}

		private void Process_RPA_Message(out byte[] txnCtx, out long applicationValue)
		{
			applicationValue = m_marshallingEngine.UnmarshalUB4();
			int num = m_marshallingEngine.UnmarshalUB2();
			if (num > 0)
			{
				txnCtx = m_marshallingEngine.UnmarshalNBytes(num);
			}
			else
			{
				txnCtx = null;
			}
		}
	}
}
